package com.gzsxy.esjy.client;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.client.discovery.event.HeartbeatMonitor;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.cloud.config.client.ConfigClientProperties;
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;

import lombok.extern.slf4j.Slf4j;

/**
 * 重写 配置客户端获取配置中心
 * @author xiaolong
 *
 */
@ConditionalOnProperty(value = "spring.cloud.config.gosuncn-discovery.enabled", matchIfMissing = false)
@Configuration
@Import({ UtilAutoConfiguration.class })
@EnableDiscoveryClient
@Slf4j
public class DiscoveryClientConfigServiceBootstrapConfiguration{

	public final static String PREFIX="spring.cloud.config.gosuncn-discovery" ;
	
	@Autowired
	private ConfigClientProperties config;

	@Autowired
	private ConfigServerInstanceProvider instanceProvider;

	private volatile boolean firstSuccess = false ;

	/**
	 * 监控配置中心,默认true,(true:配置中心启动后才启动当前项目)
	 */
	@Value("${spring.cloud.config.startAfterConfig.flag:true}")
	private boolean flag;
	
	/**
	 * 重试次数
	 */
	@Value("${spring.cloud.config.gosuncn-discovery.connected-retry:20}")
	private int connectedRetry;
	
	/**
	 * 首次延时时间(ms)
	 */
	@Value("${spring.cloud.config.gosuncn-discovery.retry-dealy:60000}")
	private long retryDelay;
	
	/**
	 * 延时时间增长指数
	 */
	@Value("${spring.cloud.config.gosuncn-discovery.dealy-speed:1.01}")
	private double delaySpeed;


	private HeartbeatMonitor monitor = new HeartbeatMonitor();
	
	
	@Bean
	public ConfigServerInstanceProvider configServerInstanceProvider(DiscoveryClient discoveryClient) {
		return new ConfigServerInstanceProvider(discoveryClient);
	}

	@EventListener(ContextRefreshedEvent.class)
	public void startup(ContextRefreshedEvent event) {
		if(flag){
			refresh();
		}
	}

	@EventListener(HeartbeatEvent.class)
	public void heartbeat(HeartbeatEvent event) {
		if (monitor.update(event.getValue()) && firstSuccess) {
			refresh();
		}
	}

	private void refresh() {
		try {
			//防止二次刷新执行
			firstSuccess = false ;
			//默认配置中心的名称为configserver
//			String serviceId = this.config.getDiscovery().getServiceId();
			String serviceId = "config-center";
			List<String> listOfUrls = new ArrayList<String>();
			List<ServiceInstance> serviceInstances = retry(serviceId) ;

			for (int i = 0; i < serviceInstances.size(); i++) {

				ServiceInstance server = serviceInstances.get(i);
				String url = getHomePage(server);

				if (server.getMetadata().containsKey("password")) {
					String user = server.getMetadata().get("user");
					user = user == null ? "user" : user;
					this.config.setUsername(user);
					String password = server.getMetadata().get("password");
					this.config.setPassword(password);
				}

				if (server.getMetadata().containsKey("configPath")) {
					String path = server.getMetadata().get("configPath");
					if (url.endsWith("/") && path.startsWith("/")) {
						url = url.substring(0, url.length() - 1);
					}
					url = url + path;
				}

				listOfUrls.add(url);
			}

			String[] uri = new String[listOfUrls.size()];
			uri = listOfUrls.toArray(uri);
			this.config.setUri(uri);
			this.firstSuccess = true ;
		} catch (Exception ex) {
			if (config.isFailFast()) {
				throw new RuntimeException(ex);
			}else {
				log.error("Could not locate configserver via discovery", ex);
			}
		}

	}
	
	/**
	 * 尝试重连
	 * @param serviceId
	 * @return
	 */
	private List<ServiceInstance> retry(String serviceId) {
		List<ServiceInstance> serviceInstances = null ;
		boolean fTry = true ;
		long time = retryDelay ;
		int num = 0 ;
		while(fTry) {
			try {
				serviceInstances = this.instanceProvider.getConfigServerInstances(serviceId);
				fTry = false ;
			}catch (Exception e) {
				
				if(num >=connectedRetry) {
					throw  new IllegalStateException("尝试多次重新连接{"+serviceId+"}失败,请确认该服务是否存在") ;
				}
				
				log.warn("检测到配置中心 {} 未启动  {}ms后重试     当前进度=[{}/{}]",serviceId,time,(1+num++),connectedRetry);
				if (Thread.currentThread().isInterrupted() ) {
	                continue ;
				}
				try {
					Thread.sleep(time);
				} catch (InterruptedException e1) {}
				time *=delaySpeed ;
			}
		}
		return serviceInstances;
		
	}

	private String getHomePage(ServiceInstance server) {
		return server.getUri().toString() + "/";
	}

}
